/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.io;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import sun.nio.cs.StreamDecoder;


/**
 * An InputStreamReader is a bridge from byte streams to character streams: It
 * reads bytes and decodes them into characters using a specified {@link
 * java.nio.charset.Charset charset}.  The charset that it uses
 * may be specified by name or may be given explicitly, or the platform's
 * default charset may be accepted.
 *
 * <p> Each invocation of one of an InputStreamReader's read() methods may
 * cause one or more bytes to be read from the underlying byte-input stream.
 * To enable the efficient conversion of bytes to characters, more bytes may
 * be read ahead from the underlying stream than are necessary to satisfy the
 * current read operation.
 *
 * <p> For top efficiency, consider wrapping an InputStreamReader within a
 * BufferedReader.  For example:
 *
 * <pre>
 * BufferedReader in
 *   = new BufferedReader(new InputStreamReader(System.in));
 * </pre>
 *
 * @author Mark Reinhold
 * @see BufferedReader
 * @see InputStream
 * @see java.nio.charset.Charset
 * @since JDK1.1
 */

public class InputStreamReader extends Reader {

  private final StreamDecoder sd;

  /**
   * Creates an InputStreamReader that uses the default charset.
   *
   * @param in An InputStream
   */
  public InputStreamReader(InputStream in) {
    super(in);
    try {
      sd = StreamDecoder.forInputStreamReader(in, this, (String) null); // ## check lock object
    } catch (UnsupportedEncodingException e) {
      // The default encoding should always be available
      throw new Error(e);
    }
  }

  /**
   * Creates an InputStreamReader that uses the named charset.
   *
   * @param in An InputStream
   * @param charsetName The name of a supported {@link java.nio.charset.Charset charset}
   * @throws UnsupportedEncodingException If the named charset is not supported
   */
  public InputStreamReader(InputStream in, String charsetName)
      throws UnsupportedEncodingException {
    super(in);
    if (charsetName == null) {
      throw new NullPointerException("charsetName");
    }
    sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
  }

  /**
   * Creates an InputStreamReader that uses the given charset.
   *
   * @param in An InputStream
   * @param cs A charset
   * @spec JSR-51
   * @since 1.4
   */
  public InputStreamReader(InputStream in, Charset cs) {
    super(in);
    if (cs == null) {
      throw new NullPointerException("charset");
    }
    sd = StreamDecoder.forInputStreamReader(in, this, cs);
  }

  /**
   * Creates an InputStreamReader that uses the given charset decoder.
   *
   * @param in An InputStream
   * @param dec A charset decoder
   * @spec JSR-51
   * @since 1.4
   */
  public InputStreamReader(InputStream in, CharsetDecoder dec) {
    super(in);
    if (dec == null) {
      throw new NullPointerException("charset decoder");
    }
    sd = StreamDecoder.forInputStreamReader(in, this, dec);
  }

  /**
   * Returns the name of the character encoding being used by this stream.
   *
   * <p> If the encoding has an historical name then that name is returned;
   * otherwise the encoding's canonical name is returned.
   *
   * <p> If this instance was created with the {@link
   * #InputStreamReader(InputStream, String)} constructor then the returned
   * name, being unique for the encoding, may differ from the name passed to
   * the constructor. This method will return <code>null</code> if the
   * stream has been closed.
   * </p>
   *
   * @return The historical name of this encoding, or <code>null</code> if the stream has been
   * closed
   * @revised 1.4
   * @spec JSR-51
   * @see java.nio.charset.Charset
   */
  public String getEncoding() {
    return sd.getEncoding();
  }

  /**
   * Reads a single character.
   *
   * @return The character read, or -1 if the end of the stream has been reached
   * @throws IOException If an I/O error occurs
   */
  public int read() throws IOException {
    return sd.read();
  }

  /**
   * Reads characters into a portion of an array.
   *
   * @param cbuf Destination buffer
   * @param offset Offset at which to start storing characters
   * @param length Maximum number of characters to read
   * @return The number of characters read, or -1 if the end of the stream has been reached
   * @throws IOException If an I/O error occurs
   */
  public int read(char cbuf[], int offset, int length) throws IOException {
    return sd.read(cbuf, offset, length);
  }

  /**
   * Tells whether this stream is ready to be read.  An InputStreamReader is
   * ready if its input buffer is not empty, or if bytes are available to be
   * read from the underlying byte stream.
   *
   * @throws IOException If an I/O error occurs
   */
  public boolean ready() throws IOException {
    return sd.ready();
  }

  public void close() throws IOException {
    sd.close();
  }
}
